/*
 * StrahlentherapiePhysicsList.cc
 *
 *  Created on: Oct 1, 2010
 *      Author: hoba
 */

#include "StrahlentherapiePhysicsList.hh"
//#include "StrahlentherapieStepMax.hh"
#include "G4PhysListFactory.hh"
#include "G4VPhysicsConstructor.hh"

// angepasste G4EmStandardPhysics_option3 ohne Myonen etc.
#include "StrahlentherapieEmStandardPhysics.hh"

// Physic lists (contained inside the Geant4 distribution)
//#include "G4EmStandardPhysics_option3.hh"
#include "G4EmLivermorePhysics.hh"
#include "G4EmPenelopePhysics.hh"
#include "G4DecayPhysics.hh"
#include "G4HadronElasticPhysics.hh"
#include "G4HadronDElasticPhysics.hh"
#include "G4HadronHElasticPhysics.hh"
#include "G4HadronQElasticPhysics.hh"
#include "G4HadronInelasticQBBC.hh"
#include "G4IonBinaryCascadePhysics.hh"
#include "G4Decay.hh"

#include "G4LossTableManager.hh"
#include "G4UnitsTable.hh"
#include "G4ProcessManager.hh"

#include "G4IonFluctuations.hh"
#include "G4IonParametrisedLossModel.hh"
#include "G4EmProcessOptions.hh"

#include "G4RadioactiveDecayPhysics.hh"

/////////////////////////////////////////////////////////////////////////////
StrahlentherapiePhysicsList::StrahlentherapiePhysicsList():G4VModularPhysicsList()
{
	emPhysicsList = 0;
	decPhysicsList = 0;

	G4LossTableManager::Instance();
	defaultCutValue = 1*mm;
	cutForGamma     = defaultCutValue;
	cutForElectron  = defaultCutValue;
	cutForPositron  = defaultCutValue;

	helIsRegisted  = false;
	bicIsRegisted  = false;
	biciIsRegisted = false;
	radioactiveDecayIsRegisted = false;

//	stepMaxProcess  = 0;

	SetVerboseLevel(1);

	// EM physics	
	AddPhysicsList("StrahlentherapieEmStandardPhysics");
//	AddPhysicsList("LowE_Livermore");
//	AddPhysicsList("LowE_Penelope");

	// Deacy physics and all particles
	decPhysicsList = new G4DecayPhysics();
}

/////////////////////////////////////////////////////////////////////////////
StrahlentherapiePhysicsList::~StrahlentherapiePhysicsList()
{
	delete emPhysicsList;
	delete decPhysicsList;
	for(size_t i=0; i<hadronPhys.size(); i++) {delete hadronPhys[i];}
}

/////////////////////////////////////////////////////////////////////////////
/*void StrahlentherapiePhysicsList::AddPackage(const G4String& name)
{
  G4PhysListFactory factory;
  G4VModularPhysicsList* phys =factory.GetReferencePhysList(name);
  G4int i=0;
  const G4VPhysicsConstructor* elem= phys->GetPhysics(i);
  G4VPhysicsConstructor* tmp = const_cast<G4VPhysicsConstructor*> (elem);
  while (elem !=0)
	{
	  RegisterPhysics(tmp);
	  elem= phys->GetPhysics(++i) ;
	  tmp = const_cast<G4VPhysicsConstructor*> (elem);
	}
}*/

/////////////////////////////////////////////////////////////////////////////
void StrahlentherapiePhysicsList::ConstructParticle()
{
  decPhysicsList->ConstructParticle();
}

/////////////////////////////////////////////////////////////////////////////
void StrahlentherapiePhysicsList::ConstructProcess()
{
  // transportation
  //
  AddTransportation();

  // electromagnetic physics list
  //
  emPhysicsList->ConstructProcess();
  em_config.AddModels();

  // decay physics list
  // fügt Zerfall für alle Partikel hinzu
  // brauchen wir eigentlich nicht, da bei uns praktisch nichts zerfallen kann, aber kostet auch keine Rechenzeit
  decPhysicsList->ConstructProcess();

  // Strahlentherapie physics lists
  for(size_t i=0; i<hadronPhys.size(); i++) {
    hadronPhys[i]->ConstructProcess();
  }

  // step limitation (as a full process)
  //
//  AddStepMax();
}

/////////////////////////////////////////////////////////////////////////////
void StrahlentherapiePhysicsList::AddPhysicsList(const G4String& name)
{

  if (verboseLevel>1) {
    G4cout << "PhysicsList::AddPhysicsList: <" << name << ">" << G4endl;
  }
  if (name == emName) return;

  /////////////////////////////////////////////////////////////////////////////
  //   ELECTROMAGNETIC MODELS
  /////////////////////////////////////////////////////////////////////////////

  if (name == "StrahlentherapieEmStandardPhysics") {
    emName = name;
    if(emPhysicsList != 0) { delete emPhysicsList; }
    emPhysicsList = new StrahlentherapieEmStandardPhysics();
    G4cout << "THE FOLLOWING ELECTROMAGNETIC PHYSICS LIST HAS BEEN ACTIVATED: StrahlentherapieEmStandardPhysics" << G4endl;

  } else if (name == "LowE_Livermore") {
    emName = name;
    if(emPhysicsList != 0) { delete emPhysicsList; }
    emPhysicsList = new G4EmLivermorePhysics();
    G4cout << "THE FOLLOWING ELECTROMAGNETIC PHYSICS LIST HAS BEEN ACTIVATED: G4EmLivermorePhysics" << G4endl;

  } else if (name == "LowE_Penelope") {
    emName = name;
    if(emPhysicsList != 0) { delete emPhysicsList; }
    emPhysicsList = new G4EmPenelopePhysics();
    G4cout << "THE FOLLOWING ELECTROMAGNETIC PHYSICS LIST HAS BEEN ACTIVATED: G4EmPenelopePhysics" << G4endl;

    /////////////////////////////////////////////////////////////////////////////
    //   HADRONIC MODELS
    /////////////////////////////////////////////////////////////////////////////
  } else if (name == "elastic" && !helIsRegisted) {
    hadronPhys.push_back( new G4HadronElasticPhysics());
    helIsRegisted = true;
    G4cout << "THE FOLLOWING HADRONIC ELASTIC PHYSICS LIST HAS BEEN ACTIVATED: G4HadronElasticPhysics()" << G4endl;
  } else if (name == "DElastic" && !helIsRegisted) {
    hadronPhys.push_back( new G4HadronDElasticPhysics());
    helIsRegisted = true;
	G4cout << "THE FOLLOWING HADRONIC ELASTIC PHYSICS LIST HAS BEEN ACTIVATED: G4HadronDElasticPhysics()" << G4endl;
  } else if (name == "HElastic" && !helIsRegisted) {
    hadronPhys.push_back( new G4HadronHElasticPhysics());
    helIsRegisted = true;
    G4cout << "THE FOLLOWING HADRONIC ELASTIC PHYSICS LIST HAS BEEN ACTIVATED: G4HadronHElasticPhysics()" << G4endl;
  } else if (name == "QElastic" && !helIsRegisted) {
    hadronPhys.push_back( new G4HadronQElasticPhysics());
    helIsRegisted = true;
	G4cout << "THE FOLLOWING HADRONIC ELASTIC PHYSICS LIST HAS BEEN ACTIVATED: G4HadronQElasticPhysics()" << G4endl;
  } else if (name == "binary" && !bicIsRegisted) {
    hadronPhys.push_back(new G4HadronInelasticQBBC());
    bicIsRegisted = true;
    G4cout << "THE FOLLOWING HADRONIC INELASTIC PHYSICS LIST HAS BEEN ACTIVATED: G4HadronInelasticQBBC()" << G4endl;

  } else if (name == "binary_ion" && !biciIsRegisted) {
    hadronPhys.push_back(new G4IonBinaryCascadePhysics());
    biciIsRegisted = true;
    G4cout << "THE FOLLOWING ION PHYSICS LIST HAS BEEN ACTIVATED: G4IonBinaryCascadePhysics()" << G4endl;
  } else if (name == "radioactive_decay" && !radioactiveDecayIsRegisted ) {
    hadronPhys.push_back(new G4RadioactiveDecayPhysics());
    radioactiveDecayIsRegisted = true;
    G4cout << "THE FOLLOWING DECAY PHYSICS LIST HAS BEEN ACTIVATED: G4RadioactiveDecayPhysics()" << G4endl;
  } else {
	G4cout << name << " " << radioactiveDecayIsRegisted << G4endl;
    G4cout << "PhysicsList::AddPhysicsList: <" << name << ">"
           << " is not defined"
           << G4endl;
  }
}

/////////////////////////////////////////////////////////////////////////////
/*void StrahlentherapiePhysicsList::AddStepMax()
{
  // Step limitation seen as a process
  stepMaxProcess = new StrahlentherapieStepMax();
stepMaxProcess->SetMaxStep(0.1);
  theParticleIterator->reset();
  while ((*theParticleIterator)()){
    G4ParticleDefinition* particle = theParticleIterator->value();
    G4ProcessManager* pmanager = particle->GetProcessManager();

    if (stepMaxProcess->IsApplicable(*particle) && pmanager) {
		pmanager->AddDiscreteProcess(stepMaxProcess);
    }
  }
}*/

/////////////////////////////////////////////////////////////////////////////
/**
 * Setzt die Laenge ab der Teilchen nicht mehr verfolgt werden.
 * Laenge wird automatisch in teilchenspezifische Energie umgerechnet.
 */
void StrahlentherapiePhysicsList::SetCuts()
{
	if (verboseLevel >0){
		G4cout << "PhysicsList::SetCuts:";
		G4cout << "CutLength : " << G4BestUnit(defaultCutValue,"Length") << G4endl;
	}

	// set cut values for gamma at first and for e- second and next for e+,
	// because some processes for e+/e- need cut values for gamma
	SetCutValue(cutForGamma, "gamma");
	SetCutValue(cutForElectron, "e-");
	SetCutValue(cutForPositron, "e+");

	if (verboseLevel>0) DumpCutValuesTable();
}

/////////////////////////////////////////////////////////////////////////////
void StrahlentherapiePhysicsList::SetCutForGamma(G4double cut)
{
  cutForGamma = cut;
  SetParticleCuts(cutForGamma, G4Gamma::Gamma());
}

/////////////////////////////////////////////////////////////////////////////
void StrahlentherapiePhysicsList::SetCutForElectron(G4double cut)
{
  cutForElectron = cut;
  SetParticleCuts(cutForElectron, G4Electron::Electron());
}

/////////////////////////////////////////////////////////////////////////////
void StrahlentherapiePhysicsList::SetCutForPositron(G4double cut)
{
  cutForPositron = cut;
  SetParticleCuts(cutForPositron, G4Positron::Positron());
}
